//
//  LSAppDelegate.m
//  LibraryStorm
//
//  Created by Enel@Lightning on 3/21/14.
//  Copyright (c) 2014 3ATeam. All rights reserved.
//

#import "LSAppDelegate.h"
#import "LSSyncEngine.h"
#import "BookCategory.h"
#import "BookDetail.h"
#import "MMDrawerController.h"
#import "MMDrawerVisualStateManager.h"
#import "AFNetworkActivityIndicatorManager.h"
#import "UIColor+HexString.h"
#import "UIImage+ColorExtension.h"
#import "LSCoreDataController.h"
#import "LSMenuViewController.h"
#import "LSDownloadManager.h"
#import "PBFlatSettings.h"
#import "LSAPIClient.h"
#import "AFHTTPRequestOperation.h"

@implementation LSAppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    // TODO: Register Push Notification on application
//    [[UIApplication sharedApplication] registerForRemoteNotificationTypes:
//     (UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)];
    
    // TODO: Setting image cache capacity
    NSURLCache *URLCache = [[NSURLCache alloc] initWithMemoryCapacity:4*1024*1024  //4MB mem cache
                                                         diskCapacity:200*1024*1024 //200MB disk cache
                                                             diskPath:@"LSURLCache"];
    [NSURLCache setSharedURLCache:URLCache];
    
    // Enable Indicator when download data
    [[AFNetworkActivityIndicatorManager sharedManager] setEnabled:YES];
    
    // TODO: Register class to sync
    [[LSSyncEngine sharedEngine] registerNSManagedObjectClassToSync:[BookCategory class]];
    [[LSSyncEngine sharedEngine] registerNSManagedObjectClassToSync:[BookDetail class]];
    
    // Override point for customization after application launch.
    MMDrawerController * drawerController = (MMDrawerController *)self.window.rootViewController;
    [drawerController setMaximumLeftDrawerWidth:(IS_DEVICE_IPAD ? LEFT_MENU_WIDTH_IPAD : LEFT_MENU_WIDTH_IPHONE)];
    [drawerController setOpenDrawerGestureModeMask:MMOpenDrawerGestureModeAll];
    [drawerController setCloseDrawerGestureModeMask:MMCloseDrawerGestureModeAll];
    [drawerController setDrawerVisualStateBlock:^(MMDrawerController *drawerController, MMDrawerSide drawerSide, CGFloat percentVisible) {
        MMDrawerControllerDrawerVisualStateBlock block;
        block = [[MMDrawerVisualStateManager sharedManager]
                 drawerVisualStateBlockForDrawerSide:drawerSide];
        if(block){
            block(drawerController, drawerSide, percentVisible);
        }
    }];

    if (SD_IS_IOS7) {
        [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];
    }
    else {
        [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleBlackOpaque];
    }

    [self customizeAppearance];
    
    // TODO: Receive push notification when app lauching
//    if (launchOptions != nil){
//        NSDictionary* dictionary = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
//        if (dictionary != nil) {
//            // do something with your dictionary
//            [self handleRemoteNotification:dictionary];
//        }
//    }

    // Load CSS file
    self.createCssRule = [[NSBundle mainBundle] URLForResource:@"AddCSSRule" withExtension:@"js" subdirectory:@"CSS"];

    // General setting
    if (![[NSUserDefaults standardUserDefaults] objectForKey:GeneralSetting]) {
        self.generalSetting = @{
                                FontFace: @(FontFaceStyle_Roboto),
                                TextSize: @(12),
                                PageTurn: @(PageTurnStyle_Fade),
                                Theme: @(ThemeStyle_White),
                                                };
        [self setGeneralSettingForEpub:self.generalSetting];
    }
    else {
        self.generalSetting = (NSDictionary *)[[NSUserDefaults standardUserDefaults] objectForKey:GeneralSetting];
    }

    return YES;
}

- (void)applicationWillResignActive:(UIApplication *)application
{
    // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
    // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
    __block UIBackgroundTaskIdentifier backgroundTaskIdentifier = [application beginBackgroundTaskWithExpirationHandler:^{
        [application endBackgroundTask:backgroundTaskIdentifier];
        [[LSDownloadManager sharedInstance] pauseAll];
        NSSet *operations = [[LSDownloadManager sharedInstance] pausedOperations];
        for (AFDownloadRequestOperation *operation in operations) {
            NSHTTPURLResponse *urlResponse = operation.response;
            NSPredicate *predicate = [NSPredicate predicateWithFormat:@"downloadLink = %@", urlResponse.URL.absoluteString];
            BookDetail *book = (BookDetail *)[BookDetail findObjectInContext:[[LSCoreDataController sharedInstance] backgroundManagedObjectContext] withPredicate:predicate];
            if (book) {
                [book setObjectInContext:[[LSCoreDataController sharedInstance] backgroundManagedObjectContext] withValue:[NSNumber numberWithInt:LSObjectDownloadPause] forKey:@"downloadStatus"];
            }
        }
        
        NSError *error = nil;
        [[LSCoreDataController sharedInstance] saveBackgroundContext];
        if (error) {
            NSLog(@"Error saving background context after creating objects on server: %@", error);
        }
        [[LSCoreDataController sharedInstance] saveMasterContext];
    }];
}

- (void)applicationDidEnterBackground:(UIApplication *)application
{
    // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 
    // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
    // TODO: Save core data when applicationDidEnterBackground
    NSError *error = nil;
    [[LSCoreDataController sharedInstance] saveBackgroundContext];
    if (error) {
        NSLog(@"Error saving background context after creating objects on server: %@", error);
    }
    [[LSCoreDataController sharedInstance] saveMasterContext];
}

- (void)applicationWillEnterForeground:(UIApplication *)application
{
    // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
}

- (void)applicationDidBecomeActive:(UIApplication *)application
{
    // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
    //TODO: Sync data when start application.
    [[LSSyncEngine sharedEngine] startSync];
    [FBAppEvents activateApp];
    /*
     Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
     */
    
    // FBSample logic
    // We need to properly handle activation of the application with regards to SSO
    //  (e.g., returning from iOS 6.0 authorization dialog or from fast app switching).
    [FBAppCall handleDidBecomeActiveWithSession:self.fbSession];
}

- (void)applicationWillTerminate:(UIApplication *)application
{
    // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
    [self.fbSession close];
}

// During the Facebook login flow, your app passes control to the Facebook iOS app or Facebook in a mobile browser.
// After authentication, your app will be called back with the session information.
- (BOOL)application:(UIApplication *)application
            openURL:(NSURL *)url
  sourceApplication:(NSString *)sourceApplication
         annotation:(id)annotation
{
    // attempt to extract a token from the url
    return [FBAppCall handleOpenURL:url
                  sourceApplication:sourceApplication
                        withSession:self.fbSession];
}

#pragma mark - Push Notification
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)devToken {
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    if (![defaults boolForKey:@"RegisterPushNotification"]) {
        NSMutableString *tokenString = nil;
        
        tokenString = [[NSMutableString alloc] initWithString:[[devToken description] uppercaseString]];
        [tokenString replaceOccurrencesOfString:@"<" withString:@"" options:0 range:NSMakeRange(0, tokenString.length)];
        [tokenString replaceOccurrencesOfString:@">" withString:@"" options:0 range:NSMakeRange(0, tokenString.length)];
        [tokenString replaceOccurrencesOfString:@" " withString:@"" options:0 range:NSMakeRange(0, tokenString.length)];
        // TODO: Register Push Notification to Parse Service
        NSMutableURLRequest *request = [[LSAPIClient sharedClient]
                                        POSTRequestForPushNotificationWithDeviceToken:tokenString];
        AFHTTPRequestOperation *operation = [[LSAPIClient sharedClient] HTTPRequestOperationWithRequest:request success:^(AFHTTPRequestOperation *operation, id responseObject) {
            NSLog(@"%@", responseObject);
            [defaults setObject:[NSNumber numberWithBool:TRUE] forKey:@"RegisterPushNotification"];
        } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
            NSLog(@"Request for APNS failed with error: %@", error);
        }];
        
        [[LSAPIClient sharedClient].operationQueue addOperation:operation];
    }
}

- (void)application:(UIApplication*)application didFailToRegisterForRemoteNotificationsWithError:(NSError*)err
{
    NSLog(@"remote notification error:%@", err);
}

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
    // TODO: Receive push notification when app active
    [self handleRemoteNotification:userInfo];
}

- (void)handleRemoteNotification:(NSDictionary *)userInfo
{
    [[LSSyncEngine sharedEngine] startSync];
}

#pragma mark - Application's Documents directory
// Returns the URL to the application's Documents directory.
- (NSURL *)applicationDocumentsDirectory
{
    return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}

#pragma mark - Date Formatter
/**
 * Method name: dateFormatter
 * Description: Create once time NSDateFormatter for all application. Using with date form parse service api.
 * Parameters: nil
 */
- (NSDateFormatter *)dateFormatter
{
    static NSDateFormatter *formatter;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        formatter = [[NSDateFormatter alloc] init];
        // Date Formatter Service
        [formatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss'Z'"];
        [formatter setTimeZone:[NSTimeZone timeZoneWithName:@"GMT"]];
    });
    return formatter;
}

- (NSDateFormatter *)customDateFormatter
{
    static NSDateFormatter *formatter;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        formatter = [[NSDateFormatter alloc] init];
        // Date Formatter Service
        [formatter setDateFormat:@"yyyyMMdd"];
    });
    return formatter;
}
#pragma mark - Decode object from dictionary
/**
 * Method name: Decode Object
 * Description: Decode many type of variable such as int, float ...; object:nsstring, nsarray, nsdictionary, nsobject
 * Parameters: NSDictionary, NSString
 */
- (id)decodeObject:(NSDictionary *)dictionary key:(NSString *)key {
    id object = [dictionary objectForKey:key];
    if (object == [NSNull null]) {
        return nil;
    }
    return object;
}

- (int)decodeInt:(NSDictionary *)dictionary key:(NSString *)key {
    id object = [dictionary objectForKey:key];
    if (object == [NSNull null]) {
        return 0;
    }
    NSNumber *number = (NSNumber *) object;
    return [number intValue];
}

- (double)decodeDouble:(NSDictionary *)dictionary key:(NSString *)key {
    id object = [dictionary objectForKey:key];
    if (object == [NSNull null]) {
        return 0;
    }
    NSNumber *number = (NSNumber *) object;
    return [number doubleValue];
}

- (float)decodeFloat:(NSDictionary *)dictionary key:(NSString *)key {
    id object = [dictionary objectForKey:key];
    if (object == [NSNull null]) {
        return 0;
    }
    NSNumber *number = (NSNumber *) object;
    return [number floatValue];
}

- (BOOL)decodeBool:(NSDictionary *)dictionary key:(NSString *)key {
    id object = [dictionary objectForKey:key];
    if (object == [NSNull null]) {
        return NO;
    }
    NSNumber *number = (NSNumber *) object;
    return [number boolValue];
}

- (NSString *)decodeString:(NSString *)source {
    if (source == nil) {
        return nil;
    }
    NSString *dec = source;
    dec = [dec stringByReplacingOccurrencesOfString:@"&gt;" withString:@">"];
    dec = [dec stringByReplacingOccurrencesOfString:@"&lt;" withString:@"<"];
    dec = [dec stringByReplacingOccurrencesOfString:@"&amp;" withString:@"&"];
    dec = [dec stringByReplacingOccurrencesOfString:@"&quot;" withString:@"\""];
    return dec;
}

- (NSString *)decodeString:(NSDictionary *)dictionary key:(NSString *)key {
    id object = [dictionary objectForKey:key];
    if (object == nil || object == [NSNull null]) {
        return nil;
    }
    return [self decodeString:(NSString *) object];
}

- (NSDate *)decodeDateObject:(NSDictionary *)dictionary key:(NSString *)key {
    NSString *value = [dictionary objectForKey:key];
    NSDate *date = [NSDate date];
    if (value != nil && value.length > 0) {
        // format for API: yyyy-MM-dd'T'HH:mm:ss'Z'
        date = [[self dateFormatter] dateFromString:value];
    }
    return date;
}

- (NSNumber *)decodeIdStr:(NSDictionary *)dictionary key:(NSString *)key {
    id object = [dictionary objectForKey:key];
    if (object == nil || [object isKindOfClass:[NSString class]] == NO) {
        return nil;
    }
    NSString *str = (NSString *) object;
    NSNumber *value = [NSNumber numberWithLongLong:[str longLongValue]];
    return value;
}

#pragma mark - Customize Appearance Of Application
/**
 * Method name: customizeAppearance
 * Description: Customize UI for all application when start. Change background of toolbar and searchbar. Customize segmentedControl: text color, offset and using FlatUI to segmentedControl
 * Parameters: nil
 */
- (void)customizeAppearance
{
    // Customize navigation title
    [[UINavigationBar appearance] setTitleTextAttributes:@{
                                                           NSForegroundColorAttributeName : [UIColor whiteColor],
                                                           NSFontAttributeName            : Roboto_Bold((IS_DEVICE_IPAD ? 22.0f : 17.5f)),
                                                           UITextAttributeTextShadowColor : [UIColor clearColor],
                                                           UITextAttributeTextShadowOffset: [NSValue valueWithUIOffset:UIOffsetMake(0, -1)]
                                                           }];

    UIImage *toolBarBackground = [[UIImage imageWithColor:[UIColor colorWithHexString:Color_Orange_View]] resizableImageWithCapInsets:UIEdgeInsetsZero];
    // Change backround color of toolBar, searchBar same as navigationBar
    [[UIToolbar appearance] setBackgroundImage:toolBarBackground forToolbarPosition:UIBarPositionAny barMetrics:UIBarMetricsDefault];
    [[UISearchBar appearance] setBackgroundImage:toolBarBackground];
    
    // Change font and color of text segmentedControl.
    NSDictionary *normalAttributes = [NSDictionary dictionaryWithObjectsAndKeys:[UIColor whiteColor] ,UITextAttributeTextColor, [NSValue valueWithUIOffset:UIOffsetMake(0, 0)], UITextAttributeTextShadowOffset, nil];
    NSDictionary *highlightedAttributes = [NSDictionary dictionaryWithObjectsAndKeys:[UIColor darkGrayColor] ,UITextAttributeTextColor, [NSValue valueWithUIOffset:UIOffsetMake(0, 0)], UITextAttributeTextShadowOffset, nil];
    [[UISegmentedControl appearance] setTitleTextAttributes:normalAttributes forState:UIControlStateNormal];
    [[UISegmentedControl appearance] setTitleTextAttributes:highlightedAttributes forState:UIControlStateHighlighted];
    [[UISegmentedControl appearance] setTitleTextAttributes:highlightedAttributes forState:UIControlStateSelected];
    
    [PBFlatSettings sharedInstance].backgroundColor = [UIColor clearColor];
    [PBFlatSettings sharedInstance].mainColor = [UIColor whiteColor];
    [PBFlatSettings sharedInstance].font = Roboto_Regular(14);
    
    // Change cancel button on searchBar
    [[UIBarButtonItem appearanceWhenContainedIn:[UISearchBar class], nil] setTitleTextAttributes:[NSDictionary dictionaryWithObjectsAndKeys:
          [UIColor whiteColor],
           UITextAttributeTextColor,
          [UIColor clearColor],
           UITextAttributeTextShadowColor,
          [NSValue valueWithUIOffset:UIOffsetMake(0, -1)],
           UITextAttributeTextShadowOffset, nil]
    forState:UIControlStateNormal];
}

#pragma mark - Setting For Epub
- (void)setGeneralSettingForEpub:(NSDictionary *)generalSetting {
    self.generalSetting = generalSetting;
    [[NSUserDefaults standardUserDefaults] setObject:generalSetting forKey:GeneralSetting];
    [[NSUserDefaults standardUserDefaults] synchronize];
}

- (NSString *)fontFamilyNameWithType:(FontFaceStyle)style
{
    NSString *fontName = @"";
    switch (style) {
        case FontFaceStyle_Arial:
            fontName = @"ArialMT";
            break;
        case FontFaceStyle_Futura:
            fontName = @"Futura-Medium";
            break;
        case FontFaceStyle_Georgia:
            fontName = @"Georgia";
            break;
        case FontFaceStyle_Helvetica:
            fontName = @"HelveticaNeue";
            break;
        case FontFaceStyle_Palantino:
            fontName = @"Palatino-Roman";
            break;
        case FontFaceStyle_Verdana:
            fontName = @"Verdana";
            break;
        case FontFaceStyle_TimesNewRoman:
            fontName = @"TimesNewRomanPSMT";
            break;
        case FontFaceStyle_Roboto:
            fontName = @"Roboto-Regular";
            break;
        default:
            break;
    }
    
    return fontName;
}

- (BOOL)limitRequestForDay
{
    
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    NSInteger count = [defaults integerForKey:LIMIT_REQUEST_KEY([[self customDateFormatter] stringFromDate:[NSDate date]])];
    if (count > 100) {
        return YES;
    }
    
    return NO;
}

- (void)increaseCountOfRequestForDay
{
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    NSInteger count = [defaults integerForKey:LIMIT_REQUEST_KEY([[self customDateFormatter] stringFromDate:[NSDate date]])];
    [defaults setObject:[NSNumber numberWithInteger:(count + 1)] forKey:LIMIT_REQUEST_KEY([[self customDateFormatter] stringFromDate:[NSDate date]])];
    [defaults synchronize];
}
@end